package org.eiahe.hr.salary.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.common.core.utils.MapstructUtils;
import org.ehe.common.core.utils.StringUtils;
import org.ehe.common.core.utils.SpringUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.system.service.ISysDeptService;
import org.springframework.stereotype.Service;
import org.eiahe.hr.salary.domain.BonusCalculation;
import org.eiahe.hr.salary.domain.BonusPayment;
import org.eiahe.hr.salary.domain.bo.BonusCalculationBo;
import org.eiahe.hr.salary.domain.vo.BonusCalculationVo;
import org.eiahe.hr.salary.mapper.BonusCalculationMapper;
import org.eiahe.hr.salary.mapper.BonusPaymentMapper;
import org.eiahe.hr.salary.service.IBonusCalculationService;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 奖金核算Service业务层处理
 *
 * @author ${author}
 * @date 2023-05-24
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class BonusCalculationServiceImpl implements IBonusCalculationService {

    private final BonusCalculationMapper baseMapper;

    /**
     * 查询奖金核算
     *
     * @param calculationId 核算ID
     * @return 奖金核算
     */
    @Override
    public BonusCalculationVo queryById(Long calculationId) {
        return baseMapper.selectVoById(calculationId);
    }

    /**
     * 根据奖金发放ID查找核算记录
     *
     * @param paymentId 奖金发放ID
     * @return 奖金核算记录
     */
    @Override
    public BonusCalculationVo queryByPaymentId(Long paymentId) {
        // 这里需要关联查询奖金发放表和核算表
        // 由于目前没有直接关联，暂时返回null
        // 实际项目中可以通过工号和奖金类型来关联查询
        return null;
    }

    /**
     * 查询奖金核算列表
     *
     * @param bo 奖金核算业务对象
     * @return 奖金核算集合
     */
    @Override
    public List<BonusCalculationVo> queryList(BonusCalculationBo bo) {
        LambdaQueryWrapper<BonusCalculation> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 分页查询奖金核算列表
     *
     * @param bo        奖金核算业务对象
     * @param pageQuery 分页参数
     * @return 奖金核算分页数据
     */
    @Override
    public TableDataInfo<BonusCalculationVo> queryPageList(BonusCalculationBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<BonusCalculation> lqw = buildQueryWrapper(bo);
        Page<BonusCalculationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 新增奖金核算
     *
     * @param bo 奖金核算业务对象
     * @return 是否成功
     */
    @Override
    public Boolean insertByBo(BonusCalculationBo bo) {
        BonusCalculation add = MapstructUtils.convert(bo, BonusCalculation.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setCalculationId(add.getCalculationId());
        }
        return flag;
    }

    /**
     * 修改奖金核算
     *
     * @param bo 奖金核算业务对象
     * @return 是否成功
     */
    @Override
    public Boolean updateByBo(BonusCalculationBo bo) {
        BonusCalculation update = MapstructUtils.convert(bo, BonusCalculation.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 删除奖金核算
     *
     * @param calculationIds 核算IDs
     * @return 是否成功
     */
    @Override
    public Boolean deleteWithValidByIds(Long[] calculationIds) {
        return baseMapper.deleteBatchIds(Arrays.asList(calculationIds)) > 0;
    }

    /**
     * 发放奖金
     *
     * @param calculationId 核算ID
     * @return 是否成功
     */
    @Override
    public Boolean payBonus(Long calculationId) {
        BonusCalculation calculation = baseMapper.selectById(calculationId);
        if (calculation == null) {
            log.warn("奖金核算记录不存在，calculationId: {}", calculationId);
            return false;
        }

        // 校验状态：只有已审核的奖金才能发放
        if (!"1".equals(calculation.getCalculationStatus())) {
            log.warn("奖金核算记录状态不正确，只有已审核的奖金才能发放，当前状态: {}", calculation.getCalculationStatus());
            throw new RuntimeException("只有已审核的奖金才能发放");
        }

        // 更新状态为已发放
        calculation.setCalculationStatus("2");
        boolean result = baseMapper.updateById(calculation) > 0;

        if (result) {
            // 同时更新奖金发放表的状态
            syncPaymentStatus(calculation);
        }

        return result;
    }

    /**
     * 处理工作流审核通过
     *
     * @param calculationId 核算ID
     * @return 是否成功
     */
    @Override
    public Boolean handleWorkflowApprove(Long calculationId) {
        BonusCalculation calculation = baseMapper.selectById(calculationId);
        if (calculation == null) {
            log.warn("奖金核算记录不存在，calculationId: {}", calculationId);
            return false;
        }

        // 校验状态：只有待审核的奖金才能进行审核操作
        if (!"0".equals(calculation.getCalculationStatus())) {
            log.warn("奖金核算记录状态不正确，只有待审核的奖金才能审核，当前状态: {}", calculation.getCalculationStatus());
            throw new RuntimeException("只有待审核的奖金才能审核");
        }

        // 更新审核状态为已审核
        calculation.setCalculationStatus("1");
        calculation.setAuditor(LoginHelper.getUsername());
        calculation.setAuditTime(new Date());

        return baseMapper.updateById(calculation) > 0;
    }

    /**
     * 处理工作流审核拒绝
     *
     * @param calculationId 核算ID
     * @return 是否成功
     */
    @Override
    public Boolean handleWorkflowReject(Long calculationId) {
        BonusCalculation calculation = baseMapper.selectById(calculationId);
        if (calculation == null) {
            log.warn("奖金核算记录不存在，calculationId: {}", calculationId);
            return false;
        }

        // 校验状态：只有待审核的奖金才能进行拒绝操作
        if (!"0".equals(calculation.getCalculationStatus())) {
            log.warn("奖金核算记录状态不正确，只有待审核的奖金才能拒绝，当前状态: {}", calculation.getCalculationStatus());
            throw new RuntimeException("只有待审核的奖金才能拒绝");
        }

        // 更新审核状态为已拒绝
        calculation.setCalculationStatus("3"); // 3表示已拒绝
        calculation.setAuditor(LoginHelper.getUsername());
        calculation.setAuditTime(new Date());

        return baseMapper.updateById(calculation) > 0;
    }

    /**
     * 同步更新奖金发放表状态
     *
     * @param calculation 奖金核算实体
     */
    private void syncPaymentStatus(BonusCalculation calculation) {
        try {
            // 注入BonusPaymentMapper
            BonusPaymentMapper paymentMapper = SpringUtils.getBean(BonusPaymentMapper.class);

            // 根据工号和奖金类型查找对应的奖金发放记录
            LambdaQueryWrapper<BonusPayment> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(BonusPayment::getEmployeeNo, calculation.getEmployeeNo());
            queryWrapper.eq(BonusPayment::getBonusType, calculation.getBonusType());

            BonusPayment payment = paymentMapper.selectOne(queryWrapper);
            if (payment != null) {
                payment.setPaymentStatus("1"); // 已发放
                paymentMapper.updateById(payment);
            }
        } catch (Exception e) {
            log.error("同步更新奖金发放表状态失败，employeeNo: {}, bonusType: {}",
                    calculation.getEmployeeNo(), calculation.getBonusType(), e);
        }
    }

    /**
     * 构建查询条件
     *
     * @param bo 奖金核算业务对象
     * @return 查询条件
     */
    private LambdaQueryWrapper<BonusCalculation> buildQueryWrapper(BonusCalculationBo bo) {
        LambdaQueryWrapper<BonusCalculation> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), BonusCalculation::getTenantId, bo.getTenantId());
        lqw.eq(StringUtils.isNotBlank(bo.getEmployeeNo()), BonusCalculation::getEmployeeNo, bo.getEmployeeNo());
        lqw.eq(StringUtils.isNotBlank(bo.getBonusType()), BonusCalculation::getBonusType, bo.getBonusType());
        lqw.eq(bo.getCalculationTime() != null, BonusCalculation::getCalculationTime, bo.getCalculationTime());
        lqw.eq(StringUtils.isNotBlank(bo.getCalculationStatus()), BonusCalculation::getCalculationStatus,
                bo.getCalculationStatus());
        return lqw;
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(BonusCalculation entity) {
        // 校验员工工号是否存在
        if (StringUtils.isBlank(entity.getEmployeeNo())) {
            throw new RuntimeException("员工工号不能为空");
        }

        // 校验员工姓名
        if (StringUtils.isBlank(entity.getEmployeeName())) {
            throw new RuntimeException("员工姓名不能为空");
        }

        // 校验奖金金额必须大于0
        if (entity.getBonusAmount() == null || entity.getBonusAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new RuntimeException("奖金金额必须大于0");
        }

        // 校验金额合理性（阈值校验）
        validBonusAmount(entity.getBonusAmount());

        // 校验奖金类型不能为空
        if (StringUtils.isBlank(entity.getBonusType())) {
            throw new RuntimeException("奖金类型不能为空");
        }

        // 校验状态合法性
        if (StringUtils.isNotBlank(entity.getCalculationStatus()) &&
                !"0".equals(entity.getCalculationStatus()) &&
                !"1".equals(entity.getCalculationStatus()) &&
                !"2".equals(entity.getCalculationStatus())) {
            throw new RuntimeException("核算状态只能是0(待审核)、1(已审核)或2(已发放)");
        }

        // 校验状态变更的合法性
        validStatusTransition(entity);
    }

    /**
     * 校验状态变更的合法性
     *
     * @param entity 奖金核算实体
     */
    private void validStatusTransition(BonusCalculation entity) {
        // 如果是更新操作，需要校验状态变更是否合法
        if (entity.getCalculationId() != null) {
            BonusCalculation oldEntity = baseMapper.selectById(entity.getCalculationId());
            if (oldEntity != null) {
                String oldStatus = oldEntity.getCalculationStatus();
                String newStatus = entity.getCalculationStatus();

                // 状态只能按顺序变更：待审核(0) → 已审核(1) → 已发放(2)
                // 不能跳过中间状态，也不能回退状态
                if ("0".equals(oldStatus) && !"0".equals(newStatus) && !"1".equals(newStatus)) {
                    throw new RuntimeException("状态变更不合法：待审核状态只能变更为已审核");
                }
                if ("1".equals(oldStatus) && !"1".equals(newStatus) && !"2".equals(newStatus)) {
                    throw new RuntimeException("状态变更不合法：已审核状态只能变更为已发放");
                }
                if ("2".equals(oldStatus) && !"2".equals(newStatus)) {
                    throw new RuntimeException("状态变更不合法：已发放状态不能变更");
                }
            }
        }
    }

    /**
     * 校验奖金金额合理性
     *
     * @param bonusAmount 奖金金额
     */
    private void validBonusAmount(BigDecimal bonusAmount) {
        // 设置金额阈值，例如单笔奖金不能超过10万元
        BigDecimal maxAmount = new BigDecimal("100000");
        if (bonusAmount.compareTo(maxAmount) > 0) {
            throw new RuntimeException("奖金金额超出阈值，单笔奖金不能超过" + maxAmount.toString());
        }

        // 不能有过多小数位
        if (bonusAmount.scale() > 2) {
            throw new RuntimeException("奖金金额小数位不能超过2位");
        }
    }
}
